/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;

import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.editpart.IUMLElementEditPart;
import com.cea.papyrus.diagram.sequence.listener.GraphElementListener;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Base class for edit parts in SeDi. This class adds an adapter to the UML model and
 * another adapter to the graphical model. The adapters call
 * {@link #graphicalModelChanged(Notification)} and {@link #umlModelChanged(Notification)}
 * so subclasses can respond appropriately.
 * 
 * @author frankd@ifi.uio.no
 * @param <T>
 *            The specific type of the UML model element that is associated with this edit
 *            part.
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public abstract class AbstractEditPart<T extends Element> extends
        org.eclipse.gef.editparts.AbstractGraphicalEditPart implements Notifier,
        IUMLElementEditPart<T> {

	/** The graph element listener. */
	protected  GraphElementListener graphElementListener;
	/** The model manager. */
	protected ModelManager modelManager;

    public AbstractEditPart(EObject model, ModelManager modelManager) {
        if (model == null)
            throw new IllegalArgumentException("null");
        setModel(model);
        this.modelManager = modelManager;
        this.graphElementListener = new GraphElementListener(this);
    }

    @Override
    public Command getCommand(Request request) {
        return super.getCommand(request);
    }

    // --- Property source ---

    /*
     * private IPropertySource propertySource; @Override public Object getAdapter(Class
     * key) { Object adapter = super.getAdapter(key); if (adapter == null && key ==
     * IPropertySource.class) { if( propertySource == null ) { propertySource = new
     * EObjectPropertySource(this.getUMLModel()); } return propertySource; } }
     */

    // --- Activation ---
    @SuppressWarnings("unchecked")
    @Override
    public void activate() {
        super.activate();
        ((EObject) getModel()).eAdapters().add(graphicalAdapter);

        T umlModel = getUmlElement();
        if (umlModel != null)
            umlModel.eAdapters().add(umlAdapter);
    }

    @Override
    public void deactivate() {
        T umlModel = getUmlElement();
        if (umlModel != null)
            umlModel.eAdapters().remove(umlAdapter);

        ((EObject) getModel()).eAdapters().remove(graphicalAdapter);
        super.deactivate();
    }

    // --- UML adapter ---

    /**
     * Responds to changes in the UML model.
     * 
     * @param evt
     *            Information about the nature of the change.
     */
    protected void umlModelChanged(Notification evt) {
        // no default action
    }

    /**
     * Listens to changes in the UML model and calls
     * {@link #umlModelChanged(Notification)} when appropriate.
     */
    protected final AdapterImpl umlAdapter = new AdapterImpl() {
        public boolean isAdapterForType(Object type) {
            return type instanceof EObject;
        }

        public void notifyChanged(Notification msg) {
            if (msg.isTouch())
                return;
            umlModelChanged(msg);
        }
    };

    // --- Graphical adapter ---

    /**
     * Responds to changes in the graphical model (the view).
     * 
     * @param evt
     *            Information about the nature of the change.
     */
    protected void graphicalModelChanged(Notification evt) {
        // no default action
    }

    /**
     * Listens to changes in the graphical model and calls
     * {@link #graphicalModelChanged(Notification)} when appropriate.
     */
    protected final AdapterImpl graphicalAdapter = new AdapterImpl() {
        public boolean isAdapterForType(Object type) {
            return type instanceof EObject;
        }

        public void notifyChanged(Notification msg) {
            if (msg.isTouch())
                return;
            graphicalModelChanged(msg);
        }
    };

    // --- Notifier ---

    public EList<Adapter> eAdapters() {
        return ((EObject) getModel()).eAdapters();
    }

    public boolean eDeliver() {
        return ((EObject) getModel()).eDeliver();
    }

    public void eSetDeliver(boolean deliver) {
        ((EObject) getModel()).eSetDeliver(deliver);
    }

    public void eNotify(Notification notification) {
        ((EObject) getModel()).eNotify(notification);
    }

    /**
     * @see com.cea.papyrus.common.editpart.IUMLElementEditPart#getUmlElement()
     */
    public T getUmlElement() {
    	return null;
    }

    /**
     * @see com.cea.papyrus.common.editpart.IUMLElementEditPart#getElementImport()
     */
    public ElementImport getElementImport() {
        return (ElementImport) this.getUmlElement();
    }

    /**
     * @see com.cea.papyrus.common.editpart.IUMLElementEditPart#isElementImport()
     */
    public boolean isElementImport() {
        return this.getUmlElement() instanceof ElementImport;
    }

    /**
     * @see com.cea.papyrus.common.editpart.IUMLElementEditPart#getModelManager()
     */
    public ModelManager getModelManager() {
        return this.modelManager;
    }

    /**
     * @see org.eclipse.ui.IActionFilter#testAttribute(java.lang.Object, java.lang.String,
     *      java.lang.String)
     */
    @SuppressWarnings("unchecked")
    public boolean testAttribute(Object target, String name, String value) {
        if (target instanceof AbstractEditPart) {
            Element targetUmlElement = ((AbstractEditPart) target).getUmlElement();
            return umlFilter.testAttribute(targetUmlElement, name, value);
        }
        return false;
    }
    
	/**
	 * 
	 * @return the GraphNode corresponding to the EditPart
	 */
	public GraphNode getGraphNode() {
		return (GraphNode) getModel();
	}
}
